package com.jzit.network.intercept

import android.os.Build
import android.text.TextUtils
import androidx.annotation.RequiresApi
import com.jzit.network.utils.LogUtils
import okhttp3.*
import java.util.ArrayList
import java.util.HashMap

/*
    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
       Author   :  zhouxc
       Date     :  2022/10/26
       Time     :  14:40
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
 */
private const val logTag = "RETROFIT_LOG"

abstract class DefaultRequestInterceptor : Interceptor {
    private val skipUrlList = ArrayList<String>()
    private val getParamMap: HashMap<String, String> = HashMap()
    private val postMultipartParamMap: HashMap<String, String> = HashMap()
    private val postFormParamMap: HashMap<String, String> = HashMap()
    private val tokenMap: HashMap<String, String> = HashMap()


    init {
        skip(skipUrlList)
    }

    abstract fun skip(skipUrlList: ArrayList<String>)
    abstract fun getDynamicParam(): Map<String, String>
    abstract fun getHeader(): Map<String, String>

    @RequiresApi(Build.VERSION_CODES.N)
    override fun intercept(chain: Interceptor.Chain): Response {
        addDynamicParam()
        var request = addHeader(chain.request())
        if (!skipUrl(request)) {
            request = addParam(request)
        }
        return chain.proceed(request)
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun addHeader(request: Request): Request {
        val header = getHeader()
        return request.newBuilder().apply {
            header.forEach { (key, value) ->
                addHeader(key, value)
            }
            tokenMap.forEach { (key, value) ->
                addHeader(key, value)
            }
        }.build()
    }

    private fun addDynamicParam() {
        val dynamicParam = getDynamicParam()
        dynamicParam.also {
            getParamMap.putAll(it)
            postFormParamMap.putAll(it)
            postMultipartParamMap.putAll(it)
            tokenMap.putAll(it)
        }
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun addParam(request: Request): Request {
        val method = request.method()
        var mRequest = request
        if (TextUtils.equals(method, "GET")) {
            mRequest = addGetParam(mRequest)
        } else if (TextUtils.equals(method, "POST")) {
            val body = request.body()
            mRequest = if (body is MultipartBody) {
                addPostMultipartParam(mRequest)
            } else {
                addPostFromParam(mRequest)
            }
        }
        return mRequest
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun addPostFromParam(mRequest: Request): Request {
        val newFormBody = FormBody.Builder()
        val oldFormBody = mRequest.body() as FormBody
        val stringBuilder = StringBuffer()
        stringBuilder.append("request : ${mRequest.url()}\n{\n\n")
        for (index in 0 until oldFormBody.size()) {
            val name = oldFormBody.name(index)
            val value = oldFormBody.value(index)
            newFormBody.add(name, value)
            stringBuilder.append("  $name:$value\n")
        }
        postFormParamMap.forEach { (key, value) ->
            newFormBody.add(key, value)
            stringBuilder.append("  ${key}:${value}\n")
        }
        stringBuilder.append("}")
        val newBuild = newFormBody.build()
        LogUtils.logI(logTag, stringBuilder.toString())
        return mRequest.newBuilder().method(mRequest.method(), newBuild).build()
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun addPostMultipartParam(mRequest: Request): Request {
        val body = mRequest.body()
        val newMultipartBody = MultipartBody.Builder()
        val oldBody = body as MultipartBody
        for (index in 0 until oldBody.size()) {
            newMultipartBody.addPart(oldBody.part(index))
        }
        postMultipartParamMap.forEach { (key, value) ->
            newMultipartBody.addFormDataPart(key, value)
        }
        val build = newMultipartBody.build()

        return mRequest.newBuilder().method(mRequest.method(), build).build()
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun addGetParam(request: Request): Request {
        val stringBuilder = StringBuffer()
        stringBuilder.append("request : ${request.url()}\n{")
        val url = request.url().newBuilder().apply {
            getParamMap.forEach { (key, value) ->
                addQueryParameter(key, value)
                stringBuilder.append("  $key:$value\n")
            }
        }.build()
        stringBuilder.append("}")
        LogUtils.logI(logTag, stringBuilder.toString())
        return request.newBuilder().url(url).build()
    }

    private fun skipUrl(request: Request): Boolean {
        var url = request.url().toString()
        if ("?" in url) {
            url = url.substring(0, url.indexOf("?"))
        }
        return url in skipUrlList
    }
}